/**
 * 项目版本添加接口测试用例
 *
 * Created by snowingsea on 2020/02/13.
 */
const chai = require('chai');
const should = chai.should(); // eslint-disable-line no-unused-vars
chai.use(require('chai-http'));
const deepcopy = require('deepcopy');
const randomstring = require('randomstring');

const common = require('./../../common');
const Administrator = require('./../../../models/administrator');
const ProjectVersion = require('./../../../models/project-version');
const uri = require('./../uri');

const projectVersions = require('./../../../../phoenix/models/project-versions');

module.exports = describe('/POST projects/:id/versions.json', function () {
  const administrator = new Administrator();
  let project;
  const newUserIds = [];
  function url(projectId) {
    if (!projectId) {
      projectId = project.projectId;
    }
    return `/projects/${projectId}/versions.json`;
  }

  before(function (done) {
    administrator.login()
      .then(() => administrator.createRandomTester())
      .then((tester) => {
        newUserIds.push(tester.userId);
        return tester.createRandomProject();
      })
      .then((res) => {
        project = res;
        done();
      })
      .catch(done);
  });
  after(function (done) {
    administrator.removeUsers(newUserIds)
      .then(() => {
        done();
      })
      .catch(done);
  });

  common.should.be.user(uri, url, 'post');
  common.should.be.tester(uri, url, 'post');

  // 正常添加项目版本
  it('it should ADD a project version successfully', function (done) {
    const versionInfo = ProjectVersion.getRandomProjectVersionInfo();
    project.creator.login()
      .then(() => {
        chai.request(uri)
          .post(url())
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .query(versionInfo)
          .end((err, res) => {
            res.should.have.status(200);
            common.should.be.projectVersionMessage(res.body);
            res.body.versionName.should.be.eql(versionInfo.versionName);
            res.body.status.should.be.eql(projectVersions.statusKind.normal);
            JSON.stringify(res.body.headers).should.be.eql(versionInfo.headers);
            JSON.stringify(res.body.languages).should.be.eql(versionInfo.languages);
            res.body.includes.should.be.eql(versionInfo.includes);
            res.body.macros.should.be.eql(JSON.parse(versionInfo.macros));
            res.body.timeout.should.be.eql(versionInfo.timeout);
            res.body.extraExit.should.be.eql(versionInfo.extraExit);
            res.body.coverages.should.be.eql(versionInfo.coverages);
            res.body.caseSensitive.should.be.eql(versionInfo.caseSensitive);
            res.body.systemType.should.be.eql(versionInfo.systemType);
            res.body.strictOutputCheck.should.be.eql(versionInfo.strictOutputCheck);
            res.body.environment.should.be.eql(versionInfo.environment);
            res.body.projectType.should.be.eql(versionInfo.projectType);
            res.body.language.should.be.eql(versionInfo.language);
            done();
          });
      })
      .catch(done);
  });

  // 请求数据分散在body中
  const keys = ['includes'];
  const data = [];
  [undefined, [], '', ['a'], ['a', 'b']].forEach((query) => {
    [undefined, [], '', ['c'], ['c', 'd']].forEach((body) => {
      let expected = [];
      if (query && body) {
        expected = query.concat(body);
      } else if (query) {
        expected = query;
      } else if (body) {
        expected = body;
      }
      data.push({ query, body, expected });
    });
  });
  keys.forEach((key) => {
    data.forEach((item) => {
      it(`it should add a project version successfully with ${key}: ${JSON.stringify(item)}`, function (done) {
        const versionInfo = ProjectVersion.getRandomProjectVersionInfo();
        versionInfo[key] = item.query;
        const body = {};
        body[key] = item.body;
        project.creator.login()
          .then(() => {
            chai.request(uri)
              .post(url())
              .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
              .query(versionInfo)
              .send(body)
              .end((err, res) => {
                res.should.have.status(200);
                common.should.be.projectVersionMessage(res.body);
                res.body[key].should.be.eql(item.expected);
                done();
              });
          })
          .catch(done);
      });
    });
  });

  // 不同项目可添加相同的版本号
  it('it should add a same project version to different project', function (done) {
    const versionInfo = ProjectVersion.getRandomProjectVersionInfo();
    project.creator.createRandomProject()
      .then((project) => project.createVersion(versionInfo))
      .then(() => project.creator.login())
      .then(() => {
        chai.request(uri)
          .post(url())
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .query(versionInfo)
          .end((err, res) => {
            res.should.have.status(200);
            common.should.be.projectVersionMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不可向不存在的项目添加版本
  it('it should fail to add a project version when the project has been removed', function (done) {
    let projectId;
    const versionInfo = ProjectVersion.getRandomProjectVersionInfo();
    project.creator.createRandomProject()
      .then((project) => {
        projectId = project.projectId;
        return project.creator.removeProject(project.projectId);
      })
      .then(() => project.creator.login())
      .then(() => {
        chai.request(uri)
          .post(url(projectId))
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .query(versionInfo)
          .end((err, res) => {
            res.should.have.status(404);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不可向他人的项目添加版本
  it('it should fail to add a project version when the project is not yours', function (done) {
    const versionInfo = ProjectVersion.getRandomProjectVersionInfo();
    administrator.createRandomTester()
      .then((newTester) => {
        newUserIds.push(newTester.userId);
        return newTester.createRandomProject();
      })
      .then(({ projectId }) => {
        chai.request(uri)
          .post(url(projectId))
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .query(versionInfo)
          .end((err, res) => {
            res.should.have.status(404);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // lastVersion被删后所在项目的lastVersion应当更新
  it('it should update lastVersion when new version is added', function (done) {
    const versionInfo = ProjectVersion.getRandomProjectVersionInfo();
    project.creator.login()
      .then(() => {
        chai.request(uri)
          .post(url())
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .query(versionInfo)
          .end((err, res) => {
            res.should.have.status(200);
            common.should.be.projectVersionMessage(res.body);
            const { versionId } = res.body;
            // 查询项目
            chai.request(uri)
              .get(`/projects/${project.projectId}.json`)
              .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
              .end((err, res) => {
                res.should.have.status(200);
                common.should.be.projectMessage(res.body);
                res.body.should.have.property('lastVersion');
                res.body.lastVersion.versionId.should.be.eql(versionId);
                done();
              });
          });
      })
      .catch(done);
  });

  // 重复添加导致失败
  it('it should fail to add project version when the version name of the project is exists', function (done) {
    const versionInfo = ProjectVersion.getRandomProjectVersionInfo();
    project.createVersion(versionInfo)
      .then(() => project.creator.login())
      .then(() => {
        chai.request(uri)
          .post(url())
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .query(versionInfo)
          .end((err, res) => {
            res.should.have.status(409);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 缺少参数
  const query = {
    versionName: ProjectVersion.getRandomProjectVersionInfo().versionName,
  };
  Object.keys(query).forEach((key) => {
    it(`it should deny invalid request of missing "${key}"`, function (done) {
      const invalidQuery = deepcopy(query);
      delete invalidQuery[key];
      project.creator.login()
        .then(() => {
          chai.request(uri)
            .post(url())
            .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
            .query(invalidQuery)
            .end((err, res) => {
              res.should.have.status(400);
              common.should.be.errorMessage(res.body);
              done();
            });
        })
        .catch(done);
    });
  });

  // macros格式不正确
  it('it should fail to add new version when macros is illegal', function (done) {
    const versionInfo = ProjectVersion.getRandomProjectVersionInfo();
    versionInfo.macros = randomstring.generate(32);
    project.creator.login()
      .then(() => {
        chai.request(uri)
          .post(url())
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .send(versionInfo)
          .end((err, res) => {
            res.should.have.status(400);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 向冻结项目添加新版本
  it('it should fail to add new version to frozen project', function (done) {
    let newProjectId;
    project.creator.createRandomProject()
      .then(({ projectId }) => {
        newProjectId = projectId;
        return project.creator.freezeProject(newProjectId);
      })
      .then(() => project.creator.login())
      .then(() => {
        chai.request(uri)
          .post(url(newProjectId))
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .query(ProjectVersion.getRandomProjectVersionInfo())
          .end((err, res) => {
            res.should.have.status(403);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });
});
